package views.folder
{
	import flash.display.DisplayObject;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	
	import gs.TweenLite;
	
	[Event(name="complete",type="flash.events.Event")]
	
	public class FolderView extends Sprite implements I_FoldableView
	{
		private var contentMask:Shape;
		private var contentContainer:Sprite;
		private var background:Shape;

		private var startPoint:Point;
		private var context:FolderViewContext;
		
		private var foldCallback:Function;
		private var unfoldCallback:Function;
		
		private var currentItems:Array;
		
		public var delegate:I_FolderViewDelegate;
		
		
		public function FolderView()
		{
			background = new Shape;
			background.alpha = 0;
			addChild(background);
			
			contentContainer = new Sprite;
			addChild(contentContainer);
			
			contentMask = new Shape;
			addChild(contentMask);
			contentContainer.mask = contentMask;
			context = new FolderViewContext;
			context.addEventListener(Event.CHANGE,updateLayout);
			context.addEventListener(Event.COMPLETE,onContentFoldComplete);
			
			addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
		}
		
		private function onContentFoldComplete(evt:Event):void
		{
			if(context.isFolded && foldCallback is Function)
			{
				foldCallback.call(null,this);
				foldCallback = null;
			}
			
			if(!context.isFolded && unfoldCallback is Function)
			{
				unfoldCallback.call(null,this);
				unfoldCallback = null;
			}
		}
		
		private function mouseDownHandler(evt:Event):void
		{
			startPoint = new Point(mouseX,mouseY);
			TweenLite.killTweensOf(context);

			addEventListener(MouseEvent.MOUSE_MOVE,mouseMoveHandler);
			addEventListener(MouseEvent.MOUSE_UP,mouseUpHandler);
			addEventListener(MouseEvent.ROLL_OUT,mouseUpHandler); 
		}
		
		private function mouseMoveHandler(evt:Event):void
		{
			contentContainer.mouseEnabled = false;
			contentContainer.mouseChildren = false;
			
			var currentPoint:Point = new Point(mouseX,mouseY);
			context.offset = context.offset + (startPoint.x - currentPoint.x);
			startPoint = currentPoint;
		}
		
		private function mouseUpHandler(evt:Event):void
		{
			var endPosition:Number = mouseX;
			context.easeOut();
			
			removeEventListener(MouseEvent.MOUSE_MOVE,mouseMoveHandler);
			removeEventListener(MouseEvent.MOUSE_UP,mouseUpHandler);
			removeEventListener(MouseEvent.ROLL_OUT,mouseUpHandler); 
			
			contentContainer.mouseEnabled = true;
			contentContainer.mouseChildren = true;
		}
		
		protected function updateLayout(evt:Event):void
		{
			while(contentContainer.numChildren > 0)
				contentContainer.removeChildAt(0);
			
			var tempViews:Array = [[]];
			for each(var itemModel:FolderViewItemModel in context.currentItems)
			{
				var view:DisplayObject;
				if(currentItems[itemModel.colIndex] is Array && currentItems[itemModel.colIndex][itemModel.rowIndex] != null)
					view = currentItems[itemModel.colIndex][itemModel.rowIndex];
				else
					view = delegate.getCellByItemModel(this,itemModel);
				
				if(view == null)
					continue;
				
				view.transform.matrix = itemModel.matrix;
				view.alpha = itemModel.alpha;
				
				contentContainer.addChild(view);
				
				tempViews[itemModel.colIndex] = tempViews[itemModel.colIndex] is Array ? tempViews[itemModel.colIndex] : new Array;
				tempViews[itemModel.colIndex][itemModel.rowIndex] = view;
			}
			currentItems = tempViews;
		}
		
		private function getMatrix(points:Array,oriPoints:Array):Matrix
		{
			var a:Number = ( (points[0].x-points[1].x)*(oriPoints[1].y-oriPoints[2].y) - (points[1].x-points[2].x)*(oriPoints[0].y-oriPoints[1].y) ) /
				( (oriPoints[0].x-oriPoints[1].x)*(oriPoints[1].y-oriPoints[2].y) - (oriPoints[1].x-oriPoints[2].x)*(oriPoints[0].y-oriPoints[1].y) );
			var c:Number = ( (points[0].x - points[1].x) - (oriPoints[0].x - oriPoints[1].x) * a) / (oriPoints[0].y - oriPoints[1].y);
			var tx:Number = points[0].x - c * oriPoints[0].y - a * oriPoints[0].x;
			
			var b:Number = ( (points[0].y-points[1].y)*(oriPoints[1].y-oriPoints[2].y) - (points[1].y-points[2].y)*(oriPoints[0].y-oriPoints[1].y) ) /
				( (oriPoints[0].x-oriPoints[1].x)*(oriPoints[1].y-oriPoints[2].y) - (oriPoints[1].x-oriPoints[2].x)*(oriPoints[0].y-oriPoints[1].y) );
			var d:Number = ( (points[0].y - points[1].y) - (oriPoints[0].x - oriPoints[1].x) * b) / (oriPoints[0].y - oriPoints[1].y);
			var ty:Number = points[0].y - d * oriPoints[0].y - b * oriPoints[0].x;
			
			
			return new Matrix(a,b,c,d,tx,ty);
		} 
			
		public function setDisplayArea(width:Number,height:Number):void
		{
			if(delegate == null)
				return;
			
			context.reset();
			currentItems = [[]];
			
			background.graphics.clear();
			background.graphics.beginFill(0xFF9900,0);
			background.graphics.drawRect(0,0,width,height);
			background.graphics.endFill();
			
			while(contentContainer.numChildren > 0)
				contentContainer.removeChildAt(0);
			
			contentMask.graphics.clear();
			contentMask.graphics.beginFill(0x9900FF,0);
			contentMask.graphics.drawRect(0,0,width,height);
			contentMask.graphics.endFill();
			
			context.initialize(width,height,
							   delegate.getColWidth(this),delegate.getRowHeight(this),
							   delegate.getColCount(this),delegate.getRowCount(this));
		}
	
		public function get isFolded():Boolean
		{
			return context.isFolded;
		}
		
		public function unfold(animated:Boolean = true,callback:Function = null):void
		{
			unfoldCallback = callback;
			context.unfold(animated);		
		}
		
		public function fold(animated:Boolean = true,callback:Function = null):void
		{
			foldCallback = callback;
			context.fold(animated);	
		}
	}
}